import pysvn
import re
import simplejson
import time
import web

render = web.template.render('templates/')

projectRegex = '([a-z][a-z0-9-_]+)'
allRegex = '(.*)'
optionalSlash = '/?'
urls = (
  '/', 'index',
  '/p/' + projectRegex + optionalSlash, 'project',
  '/p/' + projectRegex + '/svn' + optionalSlash, 'browser',
  '/stats/' + allRegex, 'stats'
)

cache = {}
MAX_CACHE = 60 # seconds

def printTiming(func):
  def wrapper(*arg):
    start = time.time()
    result = func(*arg)
    end = time.time()
    print '<hr>%s took %0.3f ms<hr>' % (func.func_name, (end-start)*1000.0)
    return result
  return wrapper

def formatDate(dateString):
  dateFormat = "%b %d %Y %H:%M:%S"
  return time.strftime(dateFormat, time.localtime(dateString))

# this is not being used
# used in get methods in stats, were this to be used:
# if (cache.has_key(repoPath) and (time.time() - cache[repoPath][0] < MAX_CACHE or getRevTime(client, repoPath) != cache[repoPath][0])):
def getRevTime(client, repoPath):
  return client.ls(repoPath,
                     recurse = False)[0]['time']

class index:
  def GET(self):
    print "NABICHT!"
    
class stats:
  GET = web.autodelegate('GET_')
  
  def parseProjects(self, queryString):
    queryString = queryString[1:]
    parameters = queryString.split('/')
    names = parameters[0].split('&')
    p = re.compile(projectRegex)
    for name in names:
      if p.match(name) == None: raise NameError
    if len(parameters) > 1:
      return names, parameters[1]
    else:
      return names, None
  
  def createProjectsStatsStructure(self, projects):
    projectsStats = []
    for project in projects:
      accessedRepository = True
      repoPath = 'http://' + project + '.googlecode.com/svn/trunk'
      thisProject = {}
      thisProject['name'] = project
      if (cache.has_key(repoPath) and (time.time() - cache[repoPath][0] < MAX_CACHE)):
        myRepository = cache[repoPath][1]
      else:
        try:
          myRepository = repository(repoPath)
          cache[repoPath] = (time.time(), myRepository)
        except:
          accessedRepository = False
          thisProject['message'] = 'Error accessing repository'
      if accessedRepository:
        thisProject['message'] = 'Time to query: ' + str(myRepository.getTime()) + ' seconds'
        thisProject['lastcommit'] = myRepository.getLastRevisionDate()
        thisProject['firstcommit'] = myRepository.getFirstRevisionDate()
        thisProject['totalcommits'] = myRepository.getTotalCommits()
        thisProject['authors'], thisProject['revisions'] = myRepository.getRevisionsByAuthor()
      else:
        thisProject['lastcommit'] = ''
        thisProject['firstcommit'] = ''
        thisProject['totalcommits'] = ''
        thisProject['authors'], thisProject['revisions'] = '',''
      projectsStats.append(thisProject)
    return projectsStats

  def GET_xml(self, queryString):
    projects = self.parseProjects(queryString)
    pass

  def GET_json(self, queryString):
    projects, callback = self.parseProjects(queryString)
    projectsStats = self.createProjectsStatsStructure(projects)
    if callback:
      print callback, '({\"projects\":', simplejson.dumps(projectsStats, indent=2), '});'
    else:
      print simplejson.dumps(projectsStats, indent=2)
    
  def GET_text(self, queryString):
    projects, callback = self.parseProjects(queryString)  
    projectsStats = self.createProjectsStatsStructure(projects)
    for projectStats in projectsStats:
      print projectStats['name']
      print ('='*len(projectStats['name']))
      print ''
      if projectStats['message'].find('Error') == -1:
        for key in projectStats.keys():
          if key == 'name': pass
          elif key == 'revisions': pass
          elif key == 'authors':
            authors = projectStats['authors']
            revisions = projectStats['revisions']
            print 'Authors: '
            for x in range(len(authors)):
              print '  ', authors[x] + ':', revisions[x]
          else:
            print key.capitalize() + ":", projectStats[key]
        print ''
      else:
        print projectStats['message']

  def GET_html(self, queryString):
    projects, callback = self.parseProjects(queryString)  
    projectsStats = self.createProjectsStatsStructure(projects)
    print '<html><head><title>Stats</title></head><body>'
    print '<h1>Stats</h1>'
    for projectStats in projectsStats:
      print '<h2>' + projectStats['name'] + '</h2>'
      if projectStats['message'].find('Error') == -1:
        print '<ul>'
        for key in projectStats.keys():
          if key == 'name': pass
          elif key == 'revisions': pass
          elif key == 'authors':
            authors = projectStats['authors']
            revisions = projectStats['revisions']
            print '<li>Authors: '
            print '<ul>'
            for x in range(len(authors)):
              print '<li>' + authors[x] + ':', str(revisions[x]) + '</li>'
            print '</ul>'
          else:
            print '<li>' + key.capitalize() + ":", str(projectStats[key]) + '</li>'
        print '</ul>'
      else:
        print '<h3>' + projectStats['message'] + '</h3>'
    print '</body></html>'

class svnClient:
  def get_login( self, realm, username, may_save ):
    retcode = False
    username = ""
    password = ""
    save = False
    return retcode, username, password, save
    
  def ssl_server_trust_prompt( self, trust_dict ):
    retcode = True
    accepted_failures = 1
    save = False
    return retcode, accepted_failures, save

  def __init__(self):
    self.client = pysvn.Client()

class repository:
  def __init__(self, repoPath):
    self.repoPath = repoPath
    self.trunkPath = repoPath + '/trunk'
    self.wikiPath = repoPath + '/wiki'
    self.client = svnClient().client
    start = time.time()
    log = self.client.log(repoPath, discover_changed_paths=True)
    self.trunkLog = []
    self.wikiLog = []
    for change in log: # not technically accurate, could be committing wiki from non-web
      if change['changed_paths'][0]['path'].startswith('/trunk'):
        self.trunkLog.append(change)
      elif change['changed_paths'][0]['path'].startswith('/wiki'):
        self.wikiLog.append(change)
    end = time.time()
    self.time = end - start

  def getRevisionsByAuthor(self):
    authors = []
    revisions = []
    revisionsByAuthors = {}
    for logEntry in self.trunkLog:
      revisionsByAuthors[logEntry['author']] = revisionsByAuthors.get(logEntry['author'], 0) + 1
    for key in revisionsByAuthors.keys():
      if key == '':
        authors.append("Anonymous")
      else: 
        authors.append(key)
      revisions.append(revisionsByAuthors[key])
    return authors, revisions

  def getLastRevisionDate(self):
    return formatDate(self.trunkLog[0]['date'])

  def getFirstRevisionDate(self):
    return formatDate(self.trunkLog[len(self.trunkLog) - 1]['date'])

  def getTotalCommits(self):
    return len(self.trunkLog)

  def getTime(self):
    return self.time
    
class project:
  @printTiming
  def GET(self, projectName):
    print render.projectHeader(projectName)
    print '<p><a href=\"/p/%s/svn\">Browse repository</a>' % projectName
    print '<hr>'
    client = svnClient().client
    repoPath = 'http://' + projectName + '.googlecode.com/svn' # not using HTTPS to solve login issue
    try:
      myRepository = repository(repoPath)
      
      print "<table border=1><tr valign=\"top\"><td>"
      print "<h2>Trunk Revisions</h2>"
      for trunkChange in myRepository.trunkLog:
          print "<h3>Revision ", trunkChange['revision'].number, "</h3>"
          print "Date: ", formatDate(trunkChange['date']), "<br>"
          print "Author: ", trunkChange['author'], "<br>"
          print "Message: ", trunkChange['message'], "<br>"
          print "<br>"
          print "Changed paths: <ul>"
          for changedPaths in trunkChange['changed_paths']:
            print "<li>", changedPaths['action'], changedPaths['path'][7:], "</li>"
          print "</ul>"
      print "</td><td>"
      print "<h2>Wiki Revisions</h2>"
      for wikiChange in myRepository.wikiLog:
        print "<h3>Revision ", wikiChange['revision'].number, "</h3>"
        print "Date: ", formatDate(wikiChange['date']), "<br>"
        print "Author: ", wikiChange['author'], "<br>"
        print "<br>"
        print "Changed paths: <ul>"
        for changedPaths in wikiChange['changed_paths']:
          print "<li>", changedPaths['action'], changedPaths['path'][6:], "</li>"
        print "</ul>"
      print "</td></tr></table>"
      
      print "<h2>Summary</h2>"
      
      print "<p>Date of first commit: ", myRepository.getFirstRevisionDate(), "</p>"
      print "<p>Date of last commit: ", myRepository.getLastRevisionDate(), "</p>"
      print "<p>Total commits: ", myRepository.getTotalCommits(),"</p>"
      print "<h3>Total commits by author:</h3>"
      authors, revisions = myRepository.getRevisionsByAuthor()
      for x in range(len(authors)):
          try:
            if authors[x] != '':
              print authors[x], ": ", revisions[x], "<br>"
            else:
              print "anonymous: ", revisions[x], "<br>"
          except e:
            print e
      # figure out what foo['changed_paths'] is doing
    except pysvn.ClientError, e:
      print "The zebras are not animatronic robots!", e

class browser:  
  @printTiming
  def GET(self, projectName):
    print render.projectHeader(projectName)
    print '<p><a href=\"/p/%s/\">Revision history</a>' % projectName
    print '<hr>'
    client = svnClient().client
    repoPath = 'http://' + projectName + '.googlecode.com/svn/trunk' # not using HTTPS to solve login issue
    try:
      repoInfo = client.ls(repoPath, recurse=False)
      print render.projectBrowser(repoPath, repoInfo, pysvn.node_kind.file)
      
      '''
      repoInfo = client.info2(repoPath)
      # print repoInfo
      
      for foo in repoInfo:
          print foo[0]
          for bar in foo[1].iterkeys():
              if bar == 'last_changed_date':
                  print bar, time.localtime(foo[1][bar])
              else:
                  print bar, foo[1][bar]
              print "<br>"
          print "<p>"
      print render.projectRepository(repoPath, repoInfo)
      '''

    except pysvn.ClientError, e:
      print "The zebras are not animatronic robots!", e
    
web.webapi.internalerror = web.debugerror
if __name__ == "__main__":
  web.run(urls, globals(), web.reloader)
